iT邦幫忙

2021 iThome 鐵人賽

DAY 20
0

Domain 間的依賴

在專案中,除了 domain 內上下層的關係外,domain 之間也會有依賴關係,而為了不讓 domain 間過度耦合,我們透過 wisper 來實現 pub-sub pattern。

關於 pub-sub pattern 的好處可以參考以下文章

延續上一篇的例子

我們現在可以利用 wisper 對所有有訂閱的 listener 發布 event,因此不再需要 marketing_client

# create_order.rb
class CreateOrder < Boxenn::UseCase
	option :repo, default: -> { OrderRepository.new }

	def steps(params:)
		subscribe_listener
		order = build_order(params)
		yield valid_order(order) # 因為回傳是 Dry::Monads::Result 所以需要 yield
		create_order(order)
		publish_event(order.serial_number)
	end

	private

  def subscribe_listener
		subscribe(::Marketing::Listener, async: true, prefix: :on)
	end

	def build_order(params)
	  OrderEntity.new(params)
	end

	def valid_order(order)
		# 假設 order entity 有個 method valid? 會回傳 Bool 告知是否合法
		return Success() if order.valid?
		
		Failure('Invalid Order')
	end

	def create_order(order)
		repo.save(order)
	end

	def publish_event(serial_number)
		publish(:order_created, order_serial_number: serial_number)
		Success() # 最後一個 call 的 method 需要回傳 Dry::Monads::Result
	end
end
# marketing_listener.rb
module Marketing
	class Listener
		class << self
			def on_invoice_created(order_serial_number:)
				result = SendPurchaseEmail.new.call(order_serial_number: order_serial_number)
				if result.failure?
					# 例外處理(打通知等等)
				end
			end
		end
	end
end

Q: 甚麼時候用 Client,甚麼時候用 pub-sub?

如果 domain 之間有明顯的上下依賴關係,則可以直接使用 client。

假設今天成立訂單後需要開立發票,而訂單和發票是不同的 domain;因為發票需要的資訊有一定的規範、介面相對穩定,設計上會傾向讓訂單依賴發票(依賴較穩定的介面),這時候成立訂單的 use case 即可直接使用發票 client 的介面。

下篇會介紹非同步的 use case 要怎麼實作。


上一篇
[DAY19] Boxenn 實作 Use Case
下一篇
[DAY21] 非同步的 Boxenn Use Case
系列文
在 Ruby on Rails 中導入 Domain-Driven Design 是不是搞錯了什麼?30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言